package com.sgzn.sgpay.service.impl;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.sgzn.sgpay.enums.*;
import com.sgzn.sgpay.exception.SgpayException;
import com.sgzn.sgpay.model.request.SgsCreditIncreaseCallBackRequest;
import com.sgzn.sgpay.model.request.SgsMchAccountUpdateRequest;
import com.sgzn.sgpay.model.request.SgsUpdateCreditRequest;
import com.sgzn.sgpay.model.response.SgsResultResponse;
import com.sgzn.sgpay.persistence.dao.TBizOrderMapper;
import com.sgzn.sgpay.persistence.dao.TMainOrderMapper;
import com.sgzn.sgpay.persistence.domain.TBizOrder;
import com.sgzn.sgpay.persistence.domain.TBizOrderExample;
import com.sgzn.sgpay.persistence.domain.TMainOrder;
import com.sgzn.sgpay.persistence.domain.TMainOrderExample;
import com.sgzn.sgpay.service.SgsCreditIncreaseCallBackService;
import com.sgzn.sgpay.service.SgsMchAccountService;
import com.sgzn.sgpay.service.SgsUpdateCreditService;
import com.sgzn.sgpay.service.support.SgsResponseUtil;
import com.sgzn.sgpay.util.TranslateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 上分回调服务接口
 * @author zhongzhongyong
 * @version Id: SgsCreditIncreaseCallBackServiceImpl.java, v 0.1 2018/4/22 15:43 zhongzhongyong Exp $$
 */
@Slf4j
@Service
@Transactional
public class SgsCreditIncreaseCallBackServiceImpl implements SgsCreditIncreaseCallBackService {

    @Autowired
    private SgsUpdateCreditService sgsUpdateCreditService;

    @Autowired
    private SgsMchAccountService sgsMchAccountService;

    @Autowired
    private TMainOrderMapper tMainOrderMapper;

    @Autowired
    private TBizOrderMapper tBizOrderMapper;

    /**
     * TCP回调上分交易
     * @return
     */
    @Override
    public SgsResultResponse<String> invoke(SgsCreditIncreaseCallBackRequest request) {
        Lock lock = new ReentrantLock();
        lock.lock();
        String orderId = "";
        try{
            //1.获取业务单信息
            TBizOrder tBizOrder = getBizOrder(request.getDeviceId());
            orderId = tBizOrder.getOrderId();
            log.info("业务单信息 tBizOrder:{}",tBizOrder);
            if(tBizOrder == null){
                throw new SgpayException(SgsResponseCode.C_VALID_ORDER_NOT_FOUND.getResponseCode(),
                        SgsResponseCode.C_VALID_ORDER_NOT_FOUND.getResponseDesc());
            }
            if(OrderStateEnum.SM_SUC.getCode().equals(tBizOrder.getBizState())){
                log.info("该上分订单已成功回调，无需重复处理.");
                return SgsResponseUtil.INSTANCE.success("success");
            }
            //只处理待回调状态的订单
            if(OrderStateEnum.SM_AFT.getCode().equals(tBizOrder.getBizState())){
                log.info("该上分订单处于待回调状态，开始处理 start handling...");
                //2.判断实际消费积分是否为0，若等于0，则表示上分失败；若大于0，则表示上分成功
                BigDecimal realAmount = tBizOrder.getBizAmount();
                boolean judgeZero = (realAmount.compareTo(BigDecimal.ZERO) == 0);
                log.info("消费积分是否为0，judgeZero:{}",judgeZero);
                if(judgeZero){
                    throw new SgpayException(SgsResponseCode.C_CREDIT_INCREASE_FAIL.getResponseCode(),
                            SgsResponseCode.C_CREDIT_INCREASE_FAIL.getResponseDesc());
                }

                //3.对用户账号进行减分
                this.updateUserAccount(request,tBizOrder.getUserId(),realAmount);

                //4.对商户账号进行加分
                this.updateMchAccount(request,tBizOrder.getOrderMerchant(),realAmount);

                //5.更新订单状态为成功
                this.updateOrder(orderId, OrderStateEnum.SM_SUC.getCode());

                log.info("SgsCreditIncreaseCallBackService invoke successfully!");
                return SgsResponseUtil.INSTANCE.success("success");
            }else{
                //已经回调失败的单，不再做任何处理
                log.info("已经回调失败的单，不再做任何处理!");
                return SgsResponseUtil.INSTANCE.fail(SgsResponseCode.C_CRED_INC_ORDER_FAIL.getResponseCode(),SgsResponseCode.C_CRED_INC_ORDER_FAIL.getResponseDesc());
            }
        }catch(SgpayException e){
            this.updateOrder(orderId, OrderStateEnum.SM_FAIL.getCode());
            log.error(" 上分业务异常 {},{}",e.getCode(),e.getDesc());
            return SgsResponseUtil.INSTANCE.fail(e.getCode(),e.getDesc());
        }catch (Exception e){
            this.updateOrder(orderId, OrderStateEnum.SM_FAIL.getCode());
            log.error(" 上分系统异常.",e);
            return SgsResponseUtil.INSTANCE.fail(SgsResponseCode.C503.getResponseCode(),SgsResponseCode.C503.getResponseDesc());
        }finally {
            lock.unlock();//释放锁
        }
    }

    /**
     * 获取业务单信息[参数：DeviceId + BizState + BizType]
     * @param deviceId
     * @return
     */
    private TBizOrder getBizOrder(String deviceId){
        TBizOrder tBizOrder = null;
        TBizOrderExample example = new TBizOrderExample();
        example.setOrderByClause(" updated_at desc ");
        TBizOrderExample.Criteria cra = example.createCriteria();
        cra.andOrderDeviceEqualTo(deviceId);
        cra.andBizStateEqualTo(OrderStateEnum.SM_AFT.getCode());
        cra.andBizTypeEqualTo(OrderTypeEnum.INCREASE_CREDIT.getCode());

        List<TBizOrder> tBizOrderList = tBizOrderMapper.selectByExample(example);
        if(CollectionUtils.isNotEmpty(tBizOrderList)){
            tBizOrder = tBizOrderList.get(0);
        }
        return tBizOrder;
    }

    /**
     * 更新用户积分
     * @param request
     */
    private void updateUserAccount(SgsCreditIncreaseCallBackRequest request,String userId,BigDecimal realAmount){
        SgsUpdateCreditRequest target = new SgsUpdateCreditRequest();
        target.setInitiationID(request.getInitiationID());
        target.setReqTime(request.getReqTime());
        target.setCredit(String.valueOf(realAmount));
        target.setUserId(userId);
        target.setTradeMark(TradeMark.DECREASE.getCode());
        if (StringUtils.isEmpty(request.getLoginChannel())) {
            target.setLoginChannel(AppName.SGT.getNumber());
        } else {
            target.setLoginChannel(request.getLoginChannel());
        }
        SgsResultResponse<Boolean> userUpdateResp = sgsUpdateCreditService.updateCredit(target);
        if(!TranslateUtil.isSuccessAbs(userUpdateResp.getErrorCode())){
            throw new SgpayException(userUpdateResp.getErrorCode(),userUpdateResp.getErrorMsg());
        }
    }

    /**
     * 更新商户账户积分
     * @param mchId
     */
    private void updateMchAccount(SgsCreditIncreaseCallBackRequest request, String mchId,BigDecimal realAmount){
        SgsMchAccountUpdateRequest target = new SgsMchAccountUpdateRequest();
        target.setInitiationID(request.getInitiationID());
        target.setLoginChannel(request.getLoginChannel());
        target.setAmount(String.valueOf(realAmount));
        target.setReqTime(request.getReqTime());
        target.setTradeMark(TradeMark.INCREASE.getCode());
        target.setMchId(mchId);
        SgsResultResponse<String> mchUpdateResp = sgsMchAccountService.updateAccountAmount(target);
        if(!TranslateUtil.isSuccessAbs(mchUpdateResp.getErrorCode())){
            throw new SgpayException(mchUpdateResp.getErrorCode(), mchUpdateResp.getErrorMsg());
        }
    }

    /**
     * 更新订单状态
     * @param orderId 主单号
     * @param orderState 订单状态
     */
    private void updateOrder(String orderId,String orderState){

        //更新主订单
        TMainOrder tMainOrder = new TMainOrder();
        tMainOrder.setOrderState(orderState);
        tMainOrder.setUpdatedAt(new Date());
        TMainOrderExample tMainOrderExample = new TMainOrderExample();
        TMainOrderExample.Criteria cra1 = tMainOrderExample.createCriteria();
        cra1.andOrderIdEqualTo(orderId);
        tMainOrderMapper.updateByExampleSelective(tMainOrder,tMainOrderExample);

        //更新业务单
        TBizOrder tBizOrder = new TBizOrder();
        tBizOrder.setBizState(orderState);
        tBizOrder.setUpdatedAt(new Date());
        TBizOrderExample tBizOrderExample = new TBizOrderExample();
        TBizOrderExample.Criteria cra2 = tBizOrderExample.createCriteria();
        cra2.andOrderIdEqualTo(orderId);
        tBizOrderMapper.updateByExampleSelective(tBizOrder,tBizOrderExample);
    }
}